package com.ict.web.service.impl;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ict.common.utils.StringUtils;
import com.ict.web.domain.ExtractExpert;
import com.ict.web.domain.IotDeviceInfo;
import com.ict.web.domain.ProjectManagement;
import com.ict.web.dto.InsertIotDeviceInfoDto;
import com.ict.web.dto.UpdateIotDeviceInfoDto;
import com.ict.web.mapper.IotDeviceInfoMapper;
import com.ict.web.service.IIotDeviceInfoService;
import com.ict.web.service.IProjectManagementService;
import com.ict.web.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

/**
 * 物联设备信息Service业务层处理
 * 
 * @author ruoyi
 * @date 2022-03-07
 */
@Service
public class IotDeviceInfoServiceImpl extends ServiceImpl<IotDeviceInfoMapper, IotDeviceInfo> implements IIotDeviceInfoService
{
    /**默认地球半径(单位m)*/
    private static double EARTH_RADIUS = 6371000;
    /**转化为弧度(rad)*/
    private static double rad(double d){
        return d * Math.PI / 180.0;
    }

    /**生产环境物联平台获取产品及其设备信息路径*/
    private static String IOT_PLATFORM_URL ="http://100.112.4.120:60010/out/getDeviceDataByProductId";
    /**测试环境物联产品及其设备文本路径*/
    private static String IOT_PLATFORM_TXT_URL ="/data01/project/yuzhongqu/service/manage/Physical_union_platform_info.txt";
//    /**生产环境物联平台获取设备信息路径**/
//    private static String IOT_PLATFORM_FACILITY_INFO_URL ="http://100.112.4.120:60010/out/getDeviceInfo";
//    /**测试环境物联设备信息文本路径*/
//    private static String IOT_PLATFORM_PRODUCT_TXT_URL ="/data01/project/yuzhongqu/service/manage/Physical_union_platform_info_tx.txt";
    @Autowired
    private IotDeviceInfoMapper iotDeviceInfoMapper;
    @Autowired
    private IProjectManagementService projectManagementService;

    @Override
    public IotDeviceInfo selectIotDeviceInfoByLotDeviceId(Long lotDeviceId) {
        IotDeviceInfo info =  iotDeviceInfoMapper.selectIotDeviceInfoByLotDeviceId(lotDeviceId);
        Assert.isTrue(info != null && !IotDeviceInfo.DELETE_STATUS_UNNORMAL.equals(info.getDelFlag()),
                "未查到此数据!!!");
        return info;
    }

    @Override
    public List<IotDeviceInfo> selectIotDeviceInfoList() {
        return iotDeviceInfoMapper.selectIotDeviceInfoList();
    }

    @Override
    public int insertIotDeviceInfo(Long programmeId, InsertIotDeviceInfoDto addDto) {
        IotDeviceInfo bean = InsertIotDeviceInfoDto.of(addDto);
        bean.setProgrammeId(programmeId);
        int result = iotDeviceInfoMapper.insert(bean);
        Assert.isTrue(result > 0,"新增物联设备信息失败!!!");
        return result;
    }

    @Override
    public int updateIotDeviceInfo(UpdateIotDeviceInfoDto updateDto) {
        IotDeviceInfo bean = UpdateIotDeviceInfoDto.of(updateDto);
        IotDeviceInfo iotDeviceInfo = this.getById(updateDto.getLotDeviceId());
        Assert.isTrue(iotDeviceInfo != null && !(iotDeviceInfo.getDelFlag().equals(IotDeviceInfo.DELETE_STATUS_UNNORMAL)),
                "未查到此数据!!!");
        return iotDeviceInfoMapper.updateById(bean);
    }

    @Override
    public int deleteIotDeviceInfoByLotDeviceId(Long lotDeviceId) {
       IotDeviceInfo bean =  iotDeviceInfoMapper.selectIotDeviceInfoByLotDeviceId(lotDeviceId);
        Assert.isTrue(bean != null && !(bean.getDelFlag().equals(IotDeviceInfo.DELETE_STATUS_UNNORMAL)),
                "未查到此数据,删除失败!!!");
        return iotDeviceInfoMapper.deleteIotDeviceInfoByLotDeviceId(lotDeviceId);
    }

    @Override
    public List<IotDeviceInfoVo> selectDeviceInfoListByProgrammeIds(Long programmeId) {
        return iotDeviceInfoMapper.selectDeviceInfoListByProgrammeIds(programmeId);
    }

    @Override
    public IntensificationExamineVo getIntensificationExamineVo(Long proId) throws ParseException {
        ProjectManagement projectManagement = projectManagementService.getById(proId);
        Assert.isTrue(StringUtils.isNotNull(projectManagement),"未找到相关项目信息");
        Assert.isTrue(StringUtils.isNotNull(projectManagement.getProgrammeId()),"项目信息不存在方案id");
        IntensificationExamineVo intensificationExamineVo = new IntensificationExamineVo();
        //申请的设备信息
        List<IotDeviceInfo> iotDeviceInfoList = iotDeviceInfoMapper.selectList(new QueryWrapper<IotDeviceInfo>().eq("programme_id", projectManagement.getProgrammeId())
                .eq("del_flag", ExtractExpert.DELETE_STATUS_NORMAL));
        if(StringUtils.isEmpty(iotDeviceInfoList)){
            return intensificationExamineVo;
        }
        //物联平台获取设备信息接口
        List<IotDeviceVo> iotDeviceList = iotDeviceInfo();
        List<GetIotDeviceInfoVo> getIotDeviceInfoVoList = new ArrayList<>();
        iotDeviceList.stream().forEach(s->{
            GetIotDeviceInfoVo getIotDeviceInfoVo = new GetIotDeviceInfoVo();
            BeanUtils.copyProperties(s,getIotDeviceInfoVo);
            getIotDeviceInfoVoList.add(getIotDeviceInfoVo);
        });
        //总重复设备
        List<GetIotDeviceInfoVo> totalList = new ArrayList<>();
        //范围内重复设备
        List<GetIotDeviceInfoVo> repetitionList = new ArrayList<>();
        //申请的全部设备
        List<GetIotDeviceInfoVo> list = new ArrayList<>();
        //重复设备
        List<GetIotDeviceInfoVo> repetitionIotList = new ArrayList<>();
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (IotDeviceInfo a:iotDeviceInfoList) {
            for (GetIotDeviceInfoVo b : getIotDeviceInfoVoList) {
                double distance = GetDistance(a.getLongitude(), a.getLatitude(), b.getLongitude(), b.getLatitude());
                BigDecimal disBigDecimal = new BigDecimal(distance);
                BigDecimal decimal = new BigDecimal(a.getRadius());
                //申请设备与物联设备距离小于申请设备的半径
                if (disBigDecimal.compareTo(decimal) <=0) {
                    GetIotDeviceInfoVo getIotDeviceInfoVo = new GetIotDeviceInfoVo();
                    BeanUtils.copyProperties(a, getIotDeviceInfoVo);
                    getIotDeviceInfoVo.setAddress(a.getConstructionSite());
                    getIotDeviceInfoVo.setId(String.valueOf(a.getLotDeviceId()));
                    getIotDeviceInfoVo.setName(a.getProductName());
                    getIotDeviceInfoVo.setCreateTime(sdf.format(a.getCreateTime()));
                    getIotDeviceInfoVo.setDeviceType(b.getDeviceType());
                    getIotDeviceInfoVo.setDeviceNum(a.getDeviceNum());
                    totalList.add(getIotDeviceInfoVo);
                    repetitionList.add(getIotDeviceInfoVo);
                    break;
                }
            }
                GetIotDeviceInfoVo getIotDeviceInfoVo = new GetIotDeviceInfoVo();
                BeanUtils.copyProperties(a,getIotDeviceInfoVo);
                getIotDeviceInfoVo.setAddress(a.getConstructionSite());
                getIotDeviceInfoVo.setId(String.valueOf(a.getLotDeviceId()));
                getIotDeviceInfoVo.setName(a.getProductName());
                getIotDeviceInfoVo.setCreateTime(sdf.format(a.getCreateTime()));
                list.add(getIotDeviceInfoVo);

            }
        //申请设备deviceType赋值
        for (GetIotDeviceInfoVo a:list) {
            for (GetIotDeviceInfoVo b : getIotDeviceInfoVoList) {
                if(a.getProductName().equals(b.getProductName())){
                    a.setDeviceType(b.getDeviceType());
                    continue;
                }
            }
            if(a.getProductName().equals("其他")){
                a.setDeviceType("other");
            }
        }
        //数据处理totalList去重、范围内重复设备为repetitionList
        List<GetIotDeviceInfoVo> totalListRes = totalList.stream().distinct().collect(Collectors.toList());
        //重复比例:申报重复数量/申报总数量
        DoubleSummaryStatistics collect = iotDeviceInfoList.stream().collect(Collectors.summarizingDouble(IotDeviceInfo::getDeviceNum));
        double iotDeviceInfoListSum = collect.getSum();
        DoubleSummaryStatistics collect1 = totalListRes.stream().collect(Collectors.summarizingDouble(GetIotDeviceInfoVo::getDeviceNum));
        double totalListResSum = collect1.getSum();
        intensificationExamineVo.setRepetition(totalListResSum / iotDeviceInfoListSum * 100);
        intensificationExamineVo.setRepetitionTotal(String.valueOf(iotDeviceInfoListSum));
        intensificationExamineVo.setRepetitionNum(String.valueOf(totalListResSum));
        //重复内容
        Map<String, Integer> result = totalListRes.stream().collect(Collectors.groupingBy(GetIotDeviceInfoVo::getName, Collectors.summingInt(GetIotDeviceInfoVo::getDeviceNum)));
        intensificationExamineVo.setRepetitionVo(result);
        //申请设备中重复的设备
        intensificationExamineVo.setIotDeviceInfoRT(repetitionList);
        //重复设备明细(重复的设备id 调取物联接口获取设备信息)
        List<IotDeviceVo> arrayList = iotDeviceInfo();
        //设备地图信息
        intensificationExamineVo.setIotDeviceInfoApply(list);
        //产品id去重
        TreeSet<GetIotDeviceInfoVo> collect2 = totalListRes.stream().collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(s -> s.getDeviceType()))));
        List<String> stringList = collect2.stream().map(GetIotDeviceInfoVo::getDeviceType).collect(Collectors.toList());
        //重复设备明细
//        List<GetIotDeviceInfoVo> collect3 = repetitionIotList.stream().collect(Collectors.collectingAndThen(
//                Collectors.toCollection(()->new ConcurrentSkipListSet<>(Comparator.comparing(GetIotDeviceInfoVo::getId))),ArrayList::new));
//
//        repetitionIotList=repetitionIotList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()->new ConcurrentSkipListSet<>
//                (Comparator.comparing(GetIotDeviceInfoVo::getLatitude).thenComparing(GetIotDeviceInfoVo::getLongitude))),ArrayList::new));
//
        //返回申请的物联设备并赋值产品id
        List<IotInfoVo> iotInfoVoList = new ArrayList<>();
        iotDeviceInfoList.stream().forEach(s->{
            IotInfoVo iotInfoVo = new IotInfoVo();
            BeanUtils.copyProperties(s,iotInfoVo);
            for (IotDeviceVo b : arrayList) {
                if(s.getProductName().equals(b.getProductName())){
                    iotInfoVo.setDeviceType(b.getDeviceType());
                }
            }
            if(iotInfoVo.getProductName().equals("其他")){
                iotInfoVo.setDeviceType("other");
            }
            iotInfoVoList.add(iotInfoVo);
        });
        intensificationExamineVo.setIotDeviceInfo(iotInfoVoList);
        return intensificationExamineVo;
    }

    /**
     * 封装返回重复物联设备信息
     * @return
     */
    public List<IotDeviceVo> iotDeviceInfo() throws ParseException {
        //生产-调用物联平台产品信息接口
//        String string = HttpUtil.createPost(IOT_PLATFORM_URL).execute().body();
        //测试-文本获取物联信息
        File file1 = new File(IOT_PLATFORM_TXT_URL);
        String string = txt2String(file1);
        //封装返回重复物联设备信息
        List<IotDeviceVo> arrayList = new ArrayList<>();
        JSONArray jsonArray = JSONObject.parseArray(string);
        for (int i = 0; i < jsonArray.size() - 1; i++) {
            String productKey = jsonArray.getJSONObject(i).getString("product_key");
            String asset = jsonArray.getJSONObject(i).getString("asset");
            String productName = jsonArray.getJSONObject(i).getString("product_name");
            JSONArray parseArray = JSONObject.parseArray(asset);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
            SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (int j = 0; j < parseArray.size(); j++) {
                IotDeviceVo iotVo = new IotDeviceVo();
                iotVo.setDeviceType(productKey);
                iotVo.setProductName(productName);
                iotVo.setDeviceStatus(parseArray.getJSONObject(j).getString("device_status"));
                iotVo.setAddress(parseArray.getJSONObject(j).getString("address"));
                String createTime = parseArray.getJSONObject(j).getString("createTime");
                //时间格式转化
                if (createTime.lastIndexOf(".") != -1) {
                    String substring = createTime.substring(0, createTime.lastIndexOf("."));
                    Date parse = simpleDateFormat.parse(substring);
                }
                Date parse = simpleDateFormat.parse(createTime);
                String format = simpleDateFormat1.format(parse);
                iotVo.setCreateTime(format);
                iotVo.setDepartmentName(parseArray.getJSONObject(j).getString("department_name"));
                iotVo.setName(parseArray.getJSONObject(j).getString("name"));
                iotVo.setId(parseArray.getJSONObject(j).getString("id"));
                iotVo.setDeviceApplicationName(parseArray.getJSONObject(j).getString("device_application_name"));
                iotVo.setLatitude(Double.valueOf(parseArray.getJSONObject(j).getString("latitude")));
                iotVo.setLongitude(Double.valueOf(parseArray.getJSONObject(j).getString("longitude")));
                arrayList.add(iotVo);
            }
        }
        return arrayList;
    }
    @Override
    public List<IotDeviceVo> select(List<String> list) throws ParseException {
        //生产-调用物联平台产品信息接口
//        String string = HttpUtil.createPost(IOT_PLATFORM_URL).execute().body();
        //测试-文本获取物联信息
        File file1 = new File(IOT_PLATFORM_TXT_URL);
        String string = txt2String(file1);
        //封装返回重复物联设备信息
        List<IotDeviceVo> arrayList = new ArrayList<>();
        JSONArray jsonArray = JSONObject.parseArray(string);
        for (int i = 0; i < jsonArray.size()-1; i++) {
            String productKey = jsonArray.getJSONObject(i).getString("product_key");
            String asset = jsonArray.getJSONObject(i).getString("asset");
            String productName = jsonArray.getJSONObject(i).getString("product_name");
            JSONArray parseArray = JSONObject.parseArray(asset);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
            SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            for (int j = 0; j < parseArray.size(); j++) {
                IotDeviceVo iotVo = new IotDeviceVo();
                iotVo.setDeviceType(productKey);
                iotVo.setProductName(productName);
                iotVo.setDeviceStatus(parseArray.getJSONObject(j).getString("device_status"));
                iotVo.setAddress(parseArray.getJSONObject(j).getString("address"));
                String createTime = parseArray.getJSONObject(j).getString("createTime");
                //时间格式转化
                if(createTime.lastIndexOf(".")!=-1){
                    String substring = createTime.substring(0, createTime.lastIndexOf("."));
                    Date parse = simpleDateFormat.parse(substring);
                }
                Date parse = simpleDateFormat.parse(createTime);
                String format = simpleDateFormat1.format(parse);
                iotVo.setCreateTime(format);
                iotVo.setDepartmentName(parseArray.getJSONObject(j).getString("department_name"));
                iotVo.setName(parseArray.getJSONObject(j).getString("name"));
                iotVo.setId(parseArray.getJSONObject(j).getString("id"));
                iotVo.setDeviceApplicationName(parseArray.getJSONObject(j).getString("device_application_name"));
                arrayList.add(iotVo);
            }

        }
        List<IotDeviceVo> iotDeviceVoList = arrayList.stream().filter(word -> list.contains(word.getDeviceType())).collect(Collectors.toList());
        return iotDeviceVoList;
    }

    @Override
    public List<IotDeviceVo> selectPage(List<IotDeviceVo> iotDeviceVoList, int pageSize, int pageNum) throws ParseException {
        return pageBySubList(iotDeviceVoList,pageSize,pageNum);
    }
    /**
     * 利用subList方法进行分页
     * @param list 分页数据
     * @param pagesize  页面大小
     * @param currentPage   当前页面
     */
    public static List pageBySubList(List list, int pagesize, int currentPage) {
        int totalcount = list.size();
        int pagecount = 0;
        List subList;
        int m = totalcount % pagesize;
        if (m > 0) {
            pagecount = totalcount / pagesize + 1;
        } else {
            pagecount = totalcount / pagesize;
        }
        if (m == 0) {
            subList = list.subList((currentPage - 1) * pagesize, pagesize * (currentPage));
        } else {
            if (currentPage == pagecount) {
                subList = list.subList((currentPage - 1) * pagesize, totalcount);
            } else {
                subList = list.subList((currentPage - 1) * pagesize, pagesize * (currentPage));
            }
        }
        return subList;
    }

    public static String txt2String(File file) {
        StringBuilder result = new StringBuilder();
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
            String s = null;
            while ((s = br.readLine()) != null) {//使用readLine方法，一次读一行
                result.append(System.lineSeparator() + s);
            }
            br.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result.toString();
    }
    /**
     * @param lon1 第一点的经度
     * @param lat1 第一点的纬度
     * @param lon2 第二点的经度
     * @param lat2 第二点的纬度
     * @return 返回的距离，单位m
     * */
    public static double GetDistance(double lon1,double lat1,double lon2, double lat2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lon1) - rad(lon2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000) / 10000;
        return s;
    }


}
